package com.essearch.service.impl;

import com.essearch.model.Req;
import com.essearch.service.ElasticsearchService;
import com.essearch.util.JsonUtil;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 *  TransportClient 索引、数据增删改查。
 */
@Service
public class ElasticsearchServiceImpl implements ElasticsearchService {
    private static final Logger logger = LoggerFactory.getLogger(ElasticsearchServiceImpl.class);

    @Resource
    private TransportClient transportClient;

    @Override
    public void insertById(String index, String type, String id, Map<String, Object> dataMap) {
        transportClient.prepareIndex(index, type, id).setSource(dataMap).get();
    }

    @Override
    public void batchInsertById(String index, String type, Map<String, Map<String, Object>> idDataMap) {
        BulkRequestBuilder bulkRequestBuilder = transportClient.prepareBulk();

        idDataMap.forEach((id, dataMap) -> bulkRequestBuilder.add(transportClient.prepareIndex(index, type, id).setSource(dataMap)));
        try {
            BulkResponse bulkResponse = bulkRequestBuilder.execute().get();
            if (bulkResponse.hasFailures()) {
                logger.error("elasticsearch批量插入错误, index=" + index + ", type=" + type + ", data=" + JsonUtil.toJson(idDataMap) + ", cause:" + bulkResponse.buildFailureMessage());
            }
        } catch (Exception e) {
            logger.error("elasticsearch批量插入错误, index=" + index + ", type=" + type + ", data=" + JsonUtil.toJson(idDataMap), e);
        }
    }

    @Override
    public void update(String index, String type, String id, Map<String, Object> dataMap) {
        this.insertById(index, type, id, dataMap);
    }

    @Override
    public void deleteById(String index, String type, String id) {
        transportClient.prepareDelete(index, type, id).get();
    }

    @Override
    public List<String> queryAllByIndex(String index, int total) {
        MatchAllQueryBuilder builder= QueryBuilders.matchAllQuery();
        SearchRequestBuilder index3 = transportClient.prepareSearch(index)
                .setQuery(builder)
                .setSize(total);
        SearchResponse searchResponse = index3.get();
        SearchHits hits =  searchResponse.getHits();
        List<String> resultList=new ArrayList<>();
        hits.forEach(hit->{
            resultList.add(hit.getSourceAsString());
        });
        return resultList;
    }

    @Override
    public List<String> queryAllByReq(String index, Req req) {
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(req.getField(),req.getValue());
        SearchRequestBuilder index1 = transportClient.prepareSearch(index).setQuery(matchQueryBuilder).setSize(10);
        SearchHits hits = index1.get().getHits();
        List<String> resultList=new ArrayList<>();
        hits.forEach(hit->{
            resultList.add(hit.getSourceAsString());
        });
        return resultList;
    }

    /**
     * 索引约束。。
     *
     * @param indexName 数据库名称
     * @param indexType 数据库表名称
     * @throws IOException
     */
    @Override
    public void createIndex(String indexName, String indexType) throws IOException {
        //表结构(建约束)
        XContentBuilder mapping = createMapping(indexType);
        //建库
        //建库建表建约束
        transportClient.admin().indices().prepareCreate(indexName).execute().actionGet();
        //建表
        PutMappingRequest putMapping = Requests.putMappingRequest(indexName).type(indexType).source(mapping);
        PutMappingResponse response = transportClient.admin().indices().putMapping(putMapping).actionGet();

        if (!response.isAcknowledged()) {
            logger.info("无法创建[" + indexName + "] [" + indexType + "]的Mapping");
        } else {
            logger.info("创建[" + indexName + "] [" + indexType + "]的Mapping成功");
        }
    }

    /**
     * @param indexType
     * @return
     */
    private XContentBuilder createMapping(String indexType) {
        XContentBuilder mapping = null;
        try {
            mapping = XContentFactory.jsonBuilder().startObject()
                    // 索引库名（类似数据库中的表）
                    .startObject(indexType).startObject("properties")
                    //id（唯一的索引）
                    .startObject("id").field("type", "string").endObject()
                    //名称
                    .startObject("productName").field("type", "string").endObject()
                    //描述
                    .startObject("productDesc").field("type", "string").endObject().endObject().endObject();

        } catch (IOException e) {
            e.printStackTrace();
        }
        return mapping;
    }

    @Override
    public void recreateIndex(String indexName) {
        try {
            //后台级的操作，关乎到删除跑路的危险
            //先清除原来已有的数据库
            transportClient.admin().indices().prepareDelete(indexName).execute().actionGet();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
